/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifndef vm_Debugger_h#define vm_Debugger_h#include"mozilla/DoublyLinkedList.h"#include"mozilla/GuardObjects.h"#include"mozilla/LinkedList.h"#include"mozilla/Range.h"#include"mozilla/TimeStamp.h"#include"mozilla/Vector.h"#include"jscntxt.h"#include"jscompartment.h"#include"jsweakmap.h"#include"jswrapper.h"#include"builtin/Promise.h"#include"ds/TraceableFifo.h"#include"gc/Barrier.h"#include"js/Debug.h"#include"js/GCVariant.h"#include"js/HashTable.h"#include"vm/GlobalObject.h"#include"vm/SavedStacks.h"#include"wasm/WasmJS.h"enumJSTrapStatus{JSTRAP_ERROR,JSTRAP_CONTINUE,JSTRAP_RETURN,JSTRAP_THROW,JSTRAP_LIMIT};namespacejs{classBreakpoint;classDebuggerMemory;classScriptedOnStepHandler;classScriptedOnPopHandler;classWasmInstanceObject;typedefHashSet<ReadBarrieredGlobalObject,MovableCellHasher<ReadBarrieredGlobalObject>,RuntimeAllocPolicy>WeakGlobalObjectSet;/* * A weakmap from GC thing keys to JSObject values that supports the keys being * in different compartments to the values. All values must be in the same * compartment. * * The purpose of this is to allow the garbage collector to easily find edges * from debuggee object compartments to debugger compartments when calculating * the compartment groups. Note that these edges are the inverse of the edges * stored in the cross compartment map. * * The current implementation results in all debuggee object compartments being * swept in the same group as the debugger. This is a conservative approach, * and compartments may be unnecessarily grouped, however it results in a * simpler and faster implementation. * * If InvisibleKeysOk is true, then the map can have keys in invisible-to- * debugger compartments. If it is false, we assert that such entries are never * created. * * Also note that keys in these weakmaps can be in any compartment, debuggee or * not, because they cannot be deleted when a compartment is no longer a * debuggee: the values need to maintain object identity across add/remove/add * transitions. */template<classUnbarrieredKey,boolInvisibleKeysOk=false>classDebuggerWeakMap:privateWeakMap<HeapPtr<UnbarrieredKey>,HeapPtr<JSObject*>,MovableCellHasher<HeapPtr<UnbarrieredKey>>>{private:typedefHeapPtr<UnbarrieredKey>Key;typedefHeapPtr<JSObject*>Value;typedefHashMap<JS::Zone*,uintptr_t,DefaultHasher<JS::Zone*>,RuntimeAllocPolicy>CountMap;CountMapzoneCounts;JSCompartment*compartment;public:typedefWeakMap<Key,Value,MovableCellHasher<Key>>Base;explicitDebuggerWeakMap(JSContext*cx):Base(cx),zoneCounts(cx->runtime()),compartment(cx->compartment()){}public:/* Expose those parts of HashMap public interface that are used by Debugger methods. */typedeftypenameBase::EntryEntry;typedeftypenameBase::PtrPtr;typedeftypenameBase::AddPtrAddPtr;typedeftypenameBase::RangeRange;typedeftypenameBase::EnumEnum;typedeftypenameBase::LookupLookup;/* Expose WeakMap public interface */usingBase::lookupForAdd;usingBase::all;usingBase::trace;MOZ_MUST_USEboolinit(uint32_tlen=16){returnBase::init(len)&&zoneCounts.init();}template<typenameKeyInput,typenameValueInput>boolrelookupOrAdd(AddPtr&p,constKeyInput&k,constValueInput&v){MOZ_ASSERT(v->compartment()==this->compartment);MOZ_ASSERT(!k->compartment()->creationOptions().mergeable());MOZ_ASSERT_IF(!InvisibleKeysOk,!k->compartment()->creationOptions().invisibleToDebugger());MOZ_ASSERT(!Base::has(k));if(!incZoneCount(k->zone()))returnfalse;boolok=Base::relookupOrAdd(p,k,v);if(!ok)decZoneCount(k->zone());returnok;}voidremove(constLookup&l){MOZ_ASSERT(Base::has(l));Base::remove(l);decZoneCount(l->zone());}public:template<void(traceValueEdges)(JSTracer*,JSObject*)>voidtraceCrossCompartmentEdges(JSTracer*tracer){for(Enume(*static_cast<Base*>(this));!e.empty();e.popFront()){traceValueEdges(tracer,e.front().value());Keykey=e.front().key();TraceEdge(tracer,&key,"Debugger WeakMap key");if(key!=e.front().key())e.rekeyFront(key);key.unsafeSet(nullptr);}}boolhasKeyInZone(JS::Zone*zone){CountMap::Ptrp=zoneCounts.lookup(zone);MOZ_ASSERT_IF(p.found(),p->value()>0);returnp.found();}private:/* Override sweep method to also update our edge cache. */voidsweep(){MOZ_ASSERT(CurrentThreadIsPerformingGC());for(Enume(*static_cast<Base*>(this));!e.empty();e.popFront()){if(gc::IsAboutToBeFinalized(&e.front().mutableKey())){decZoneCount(e.front().key()->zoneFromAnyThread());e.removeFront();}}Base::assertEntriesNotAboutToBeFinalized();}MOZ_MUST_USEboolincZoneCount(JS::Zone*zone){CountMap::Ptrp=zoneCounts.lookupWithDefault(zone,0);if(!p)returnfalse;++p->value();returntrue;}voiddecZoneCount(JS::Zone*zone){CountMap::Ptrp=zoneCounts.lookup(zone);MOZ_ASSERT(p);MOZ_ASSERT(p->value()>0);--p->value();if(p->value()==0)zoneCounts.remove(zone);}};classLeaveDebuggeeNoExecute;// Suppresses all debuggee NX checks, i.e., allow all execution. Used to allow// certain whitelisted operations to execute code.//// WARNING// WARNING Do not use this unless you know what you are doing!// WARNINGclassAutoSuppressDebuggeeNoExecuteChecks{EnterDebuggeeNoExecute**stack_;EnterDebuggeeNoExecute*prev_;public:explicitAutoSuppressDebuggeeNoExecuteChecks(JSContext*cx){stack_=&cx->noExecuteDebuggerTop.ref();prev_=*stack_;*stack_=nullptr;}~AutoSuppressDebuggeeNoExecuteChecks(){MOZ_ASSERT(!*stack_);*stack_=prev_;}};classMOZ_RAIIEvalOptions{constchar*filename_;unsignedlineno_;public:EvalOptions():filename_(nullptr),lineno_(1){}~EvalOptions();constchar*filename()const{returnfilename_;}unsignedlineno()const{returnlineno_;}MOZ_MUST_USEboolsetFilename(JSContext*cx,constchar*filename);voidsetLineno(unsignedlineno){lineno_=lineno;}};/* * Env is the type of what ES5 calls "lexical environments" (runtime activations * of lexical scopes). This is currently just JSObject, and is implemented by * CallObject, LexicalEnvironmentObject, and WithEnvironmentObject, among * others--but environments and objects are really two different concepts. */typedefJSObjectEnv;// Either a real JSScript or synthesized.//// If synthesized, the referent is one of the following://// 1. A WasmInstanceObject, denoting a synthesized toplevel wasm module// script.// 2. A wasm JSFunction, denoting a synthesized wasm function script.// NYI!typedefmozilla::Variant<JSScript*,WasmInstanceObject*>DebuggerScriptReferent;// Either a ScriptSourceObject, for ordinary JS, or a WasmInstanceObject,// denoting the synthesized source of a wasm module.typedefmozilla::Variant<ScriptSourceObject*,WasmInstanceObject*>DebuggerSourceReferent;// Either a AbstractFramePtr, for ordinary JS, or a wasm::DebugFrame,// for synthesized frame of a wasm code.typedefmozilla::Variant<AbstractFramePtr,wasm::DebugFrame*>DebuggerFrameReferent;classDebugger:privatemozilla::LinkedListElement<Debugger>{friendclassBreakpoint;friendclassDebuggerMemory;friendstructJSRuntime::GlobalObjectWatchersSiblingAccess<Debugger>;friendclassSavedStacks;friendclassScriptedOnStepHandler;friendclassScriptedOnPopHandler;friendclassmozilla::LinkedListElement<Debugger>;friendclassmozilla::LinkedList<Debugger>;friendbool(::JS_DefineDebuggerObject)(JSContext*cx,JS::HandleObjectobj);friendbool(::JS::dbg::IsDebugger)(JSObject&);friendbool(::JS::dbg::GetDebuggeeGlobals)(JSContext*,JSObject&,AutoObjectVector&);friendvoidJS::dbg::onNewPromise(JSContext*cx,HandleObjectpromise);friendvoidJS::dbg::onPromiseSettled(JSContext*cx,HandleObjectpromise);friendboolJS::dbg::FireOnGarbageCollectionHook(JSContext*cx,JS::dbg::GarbageCollectionEvent::Ptr&&data);public:enumHook{OnDebuggerStatement,OnExceptionUnwind,OnNewScript,OnEnterFrame,OnNewGlobalObject,OnNewPromise,OnPromiseSettled,OnGarbageCollection,HookCount};enum{JSSLOT_DEBUG_PROTO_START,JSSLOT_DEBUG_FRAME_PROTO=JSSLOT_DEBUG_PROTO_START,JSSLOT_DEBUG_ENV_PROTO,JSSLOT_DEBUG_OBJECT_PROTO,JSSLOT_DEBUG_SCRIPT_PROTO,JSSLOT_DEBUG_SOURCE_PROTO,JSSLOT_DEBUG_MEMORY_PROTO,JSSLOT_DEBUG_PROTO_STOP,JSSLOT_DEBUG_HOOK_START=JSSLOT_DEBUG_PROTO_STOP,JSSLOT_DEBUG_HOOK_STOP=JSSLOT_DEBUG_HOOK_START+HookCount,JSSLOT_DEBUG_MEMORY_INSTANCE=JSSLOT_DEBUG_HOOK_STOP,JSSLOT_DEBUG_COUNT};classExecutionObservableSet{public:typedefHashSet<Zone*>::RangeZoneRange;virtualZone*singleZone()const{returnnullptr;}virtualJSScript*singleScriptForZoneInvalidation()const{returnnullptr;}virtualconstHashSet<Zone*>*zones()const{returnnullptr;}virtualboolshouldRecompileOrInvalidate(JSScript*script)const=0;virtualboolshouldMarkAsDebuggee(FrameIter&iter)const=0;};// This enum is converted to and compare with bool values; NotObserving// must be 0 and Observing must be 1.enumIsObserving{NotObserving=0,Observing=1};// Return true if the given compartment is a debuggee of this debugger,// false otherwise.boolisDebuggeeUnbarriered(constJSCompartment*compartment)const;// Return true if this Debugger observed a debuggee that participated in the// GC identified by the given GC number. Return false otherwise.// May return false negatives if we have hit OOM.boolobservedGC(uint64_tmajorGCNumber)const{returnobservedGCs.has(majorGCNumber);}// Notify this Debugger that one or more of its debuggees is participating// in the GC identified by the given GC number.booldebuggeeIsBeingCollected(uint64_tmajorGCNumber){returnobservedGCs.put(majorGCNumber);}boolisEnabled()const{returnenabled;}staticSavedFrame*getObjectAllocationSite(JSObject&obj);structAllocationsLogEntry{AllocationsLogEntry(HandleObjectframe,mozilla::TimeStampwhen,constchar*className,HandleAtomctorName,size_tsize,boolinNursery):frame(frame),when(when),className(className),ctorName(ctorName),size(size),inNursery(inNursery){MOZ_ASSERT_IF(frame,UncheckedUnwrap(frame)->is<SavedFrame>());};HeapPtr<JSObject*>frame;mozilla::TimeStampwhen;constchar*className;HeapPtr<JSAtom*>ctorName;size_tsize;boolinNursery;voidtrace(JSTracer*trc){TraceNullableEdge(trc,&frame,"Debugger::AllocationsLogEntry::frame");TraceNullableEdge(trc,&ctorName,"Debugger::AllocationsLogEntry::ctorName");}};// Barrier methods so we can have ReadBarriered<Debugger*>.staticvoidreadBarrier(Debugger*dbg){InternalBarrierMethods<JSObject*>::readBarrier(dbg->object);}staticvoidwriteBarrierPost(Debugger**vp,Debugger*prev,Debugger*next){}private:GCPtrNativeObjectobject;/* The Debugger object. Strong reference. */WeakGlobalObjectSetdebuggees;/* Debuggee globals. Cross-compartment weak references. */JS::ZoneSetdebuggeeZones;/* Set of zones that we have debuggees in. */js::GCPtrObjectuncaughtExceptionHook;/* Strong reference. */boolenabled;boolallowUnobservedAsmJS;boolallowWasmBinarySource;// Whether to enable code coverage on the Debuggee.boolcollectCoverageInfo;template<typenameT>structDebuggerSiblingAccess{staticT*GetNext(T*elm){returnelm->debuggerLink.mNext;}staticvoidSetNext(T*elm,T*next){elm->debuggerLink.mNext=next;}staticT*GetPrev(T*elm){returnelm->debuggerLink.mPrev;}staticvoidSetPrev(T*elm,T*prev){elm->debuggerLink.mPrev=prev;}};// List of all js::Breakpoints in this debugger.usingBreakpointList=mozilla::DoublyLinkedList<js::Breakpoint,DebuggerSiblingAccess<js::Breakpoint>>;BreakpointListbreakpoints;// The set of GC numbers for which one or more of this Debugger's observed// debuggees participated in.usingGCNumberSet=HashSet<uint64_t,DefaultHasher<uint64_t>,RuntimeAllocPolicy>;GCNumberSetobservedGCs;usingAllocationsLog=js::TraceableFifo<AllocationsLogEntry>;AllocationsLogallocationsLog;booltrackingAllocationSites;doubleallocationSamplingProbability;size_tmaxAllocationsLogLength;boolallocationsLogOverflowed;staticconstsize_tDEFAULT_MAX_LOG_LENGTH=5000;MOZ_MUST_USEboolappendAllocationSite(JSContext*cx,HandleObjectobj,HandleSavedFrameframe,mozilla::TimeStampwhen);/* * Recompute the set of debuggee zones based on the set of debuggee globals. */voidrecomputeDebuggeeZoneSet();/* * Return true if there is an existing object metadata callback for the * given global's compartment that will prevent our instrumentation of * allocations. */staticboolcannotTrackAllocations(constGlobalObject&global);/* * Return true if the given global is being observed by at least one * Debugger that is tracking allocations. */staticboolisObservedByDebuggerTrackingAllocations(constGlobalObject&global);/* * Add allocations tracking for objects allocated within the given * debuggee's compartment. The given debuggee global must be observed by at * least one Debugger that is enabled and tracking allocations. */staticMOZ_MUST_USEbooladdAllocationsTracking(JSContext*cx,Handle<GlobalObject*>debuggee);/* * Remove allocations tracking for objects allocated within the given * global's compartment. This is a no-op if there are still Debuggers * observing this global and who are tracking allocations. */staticvoidremoveAllocationsTracking(GlobalObject&global);/* * Add or remove allocations tracking for all debuggees. */MOZ_MUST_USEbooladdAllocationsTrackingForAllDebuggees(JSContext*cx);voidremoveAllocationsTrackingForAllDebuggees();/* * If this Debugger is enabled, and has a onNewGlobalObject handler, then * this link is inserted into the list headed by * JSRuntime::onNewGlobalObjectWatchers. */mozilla::DoublyLinkedListElement<Debugger>onNewGlobalObjectWatchersLink;/* * Map from stack frames that are currently on the stack to Debugger.Frame * instances. * * The keys are always live stack frames. We drop them from this map as * soon as they leave the stack (see slowPathOnLeaveFrame) and in * removeDebuggee. * * We don't trace the keys of this map (the frames are on the stack and * thus necessarily live), but we do trace the values. It's like a WeakMap * that way, but since stack frames are not gc-things, the implementation * has to be different. */typedefHashMap<AbstractFramePtr,HeapPtr<DebuggerFrame*>,DefaultHasher<AbstractFramePtr>,RuntimeAllocPolicy>FrameMap;FrameMapframes;/* An ephemeral map from JSScript* to Debugger.Script instances. */typedefDebuggerWeakMap<JSScript*>ScriptWeakMap;ScriptWeakMapscripts;/* The map from debuggee source script objects to their Debugger.Source instances. */typedefDebuggerWeakMap<JSObject*,true>SourceWeakMap;SourceWeakMapsources;/* The map from debuggee objects to their Debugger.Object instances. */typedefDebuggerWeakMap<JSObject*>ObjectWeakMap;ObjectWeakMapobjects;/* The map from debuggee Envs to Debugger.Environment instances. */ObjectWeakMapenvironments;/* The map from WasmInstanceObjects to synthesized Debugger.Script instances. */typedefDebuggerWeakMap<WasmInstanceObject*>WasmInstanceWeakMap;WasmInstanceWeakMapwasmInstanceScripts;/* The map from WasmInstanceObjects to synthesized Debugger.Source instances. */WasmInstanceWeakMapwasmInstanceSources;/* * Keep track of tracelogger last drained identifiers to know if there are * lost events. */#ifdef NIGHTLY_BUILDuint32_ttraceLoggerLastDrainedSize;uint32_ttraceLoggerLastDrainedIteration;#endifuint32_ttraceLoggerScriptedCallsLastDrainedSize;uint32_ttraceLoggerScriptedCallsLastDrainedIteration;classScriptQuery;classObjectQuery;MOZ_MUST_USEbooladdDebuggeeGlobal(JSContext*cx,Handle<GlobalObject*>obj);voidremoveDebuggeeGlobal(FreeOp*fop,GlobalObject*global,WeakGlobalObjectSet::Enum*debugEnum);/* * Report and clear the pending exception on ac.context, if any, and return * JSTRAP_ERROR. */JSTrapStatusreportUncaughtException(mozilla::Maybe<AutoCompartment>&ac);/* * Cope with an error or exception in a debugger hook. * * If callHook is true, then call the uncaughtExceptionHook, if any. If, in * addition, vp is given, then parse the value returned by * uncaughtExceptionHook as a resumption value. * * If there is no uncaughtExceptionHook, or if it fails, report and clear * the pending exception on ac.context and return JSTRAP_ERROR. * * This always calls ac.leave(); ac is a parameter because this method must * do some things in the debugger compartment and some things in the * debuggee compartment. */JSTrapStatushandleUncaughtException(mozilla::Maybe<AutoCompartment>&ac);JSTrapStatushandleUncaughtException(mozilla::Maybe<AutoCompartment>&ac,MutableHandleValuevp,constmozilla::Maybe<HandleValue>&thisVForCheck=mozilla::Nothing(),AbstractFramePtrframe=NullFramePtr());JSTrapStatushandleUncaughtExceptionHelper(mozilla::Maybe<AutoCompartment>&ac,MutableHandleValue*vp,constmozilla::Maybe<HandleValue>&thisVForCheck,AbstractFramePtrframe);/* * Handle the result of a hook that is expected to return a resumption * value <https://wiki.mozilla.org/Debugger#Resumption_Values>. This is called * when we return from a debugging hook to debuggee code. The interpreter wants * a (JSTrapStatus, Value) pair telling it how to proceed. * * Precondition: ac is entered. We are in the debugger compartment. * * Postcondition: This called ac.leave(). See handleUncaughtException. * * If ok is false, the hook failed. If an exception is pending in * ac.context(), return handleUncaughtException(ac, vp, callhook). * Otherwise just return JSTRAP_ERROR. * * If ok is true, there must be no exception pending in ac.context(). rv may be: * undefined - Return JSTRAP_CONTINUE to continue execution normally. * {return: value} or {throw: value} - Call unwrapDebuggeeValue to * unwrap value. Store the result in *vp and return JSTRAP_RETURN * or JSTRAP_THROW. The interpreter will force the current frame to * return or throw an exception. * null - Return JSTRAP_ERROR to terminate the debuggee with an * uncatchable error. * anything else - Make a new TypeError the pending exception and * return handleUncaughtException(ac, vp, callHook). */JSTrapStatusprocessHandlerResult(mozilla::Maybe<AutoCompartment>&ac,boolOK,constValue&rv,AbstractFramePtrframe,jsbytecode*pc,MutableHandleValuevp);JSTrapStatusprocessParsedHandlerResult(mozilla::Maybe<AutoCompartment>&ac,AbstractFramePtrframe,jsbytecode*pc,boolsuccess,JSTrapStatusstatus,MutableHandleValuevp);JSTrapStatusprocessParsedHandlerResultHelper(mozilla::Maybe<AutoCompartment>&ac,AbstractFramePtrframe,constmozilla::Maybe<HandleValue>&maybeThisv,boolsuccess,JSTrapStatusstatus,MutableHandleValuevp);boolprocessResumptionValue(mozilla::Maybe<AutoCompartment>&ac,AbstractFramePtrframe,constmozilla::Maybe<HandleValue>&maybeThis,HandleValuerval,JSTrapStatus&statusp,MutableHandleValuevp);GlobalObject*unwrapDebuggeeArgument(JSContext*cx,constValue&v);staticvoidtraceObject(JSTracer*trc,JSObject*obj);voidtrace(JSTracer*trc);friendstructjs::GCManagedDeletePolicy<Debugger>;voidtraceForMovingGC(JSTracer*trc);voidtraceCrossCompartmentEdges(JSTracer*tracer);staticconstClassOpsclassOps_;public:staticconstClassclass_;private:staticMOZ_MUST_USEboolgetHookImpl(JSContext*cx,CallArgs&args,Debugger&dbg,Hookwhich);staticMOZ_MUST_USEboolsetHookImpl(JSContext*cx,CallArgs&args,Debugger&dbg,Hookwhich);staticboolgetEnabled(JSContext*cx,unsignedargc,Value*vp);staticboolsetEnabled(JSContext*cx,unsignedargc,Value*vp);staticboolgetOnDebuggerStatement(JSContext*cx,unsignedargc,Value*vp);staticboolsetOnDebuggerStatement(JSContext*cx,unsignedargc,Value*vp);staticboolgetOnExceptionUnwind(JSContext*cx,unsignedargc,Value*vp);staticboolsetOnExceptionUnwind(JSContext*cx,unsignedargc,Value*vp);staticboolgetOnNewScript(JSContext*cx,unsignedargc,Value*vp);staticboolsetOnNewScript(JSContext*cx,unsignedargc,Value*vp);staticboolgetOnEnterFrame(JSContext*cx,unsignedargc,Value*vp);staticboolsetOnEnterFrame(JSContext*cx,unsignedargc,Value*vp);staticboolgetOnNewGlobalObject(JSContext*cx,unsignedargc,Value*vp);staticboolsetOnNewGlobalObject(JSContext*cx,unsignedargc,Value*vp);staticboolgetOnNewPromise(JSContext*cx,unsignedargc,Value*vp);staticboolsetOnNewPromise(JSContext*cx,unsignedargc,Value*vp);staticboolgetOnPromiseSettled(JSContext*cx,unsignedargc,Value*vp);staticboolsetOnPromiseSettled(JSContext*cx,unsignedargc,Value*vp);staticboolgetUncaughtExceptionHook(JSContext*cx,unsignedargc,Value*vp);staticboolsetUncaughtExceptionHook(JSContext*cx,unsignedargc,Value*vp);staticboolgetAllowUnobservedAsmJS(JSContext*cx,unsignedargc,Value*vp);staticboolsetAllowUnobservedAsmJS(JSContext*cx,unsignedargc,Value*vp);staticboolgetAllowWasmBinarySource(JSContext*cx,unsignedargc,Value*vp);staticboolsetAllowWasmBinarySource(JSContext*cx,unsignedargc,Value*vp);staticboolgetCollectCoverageInfo(JSContext*cx,unsignedargc,Value*vp);staticboolsetCollectCoverageInfo(JSContext*cx,unsignedargc,Value*vp);staticboolgetMemory(JSContext*cx,unsignedargc,Value*vp);staticbooladdDebuggee(JSContext*cx,unsignedargc,Value*vp);staticbooladdAllGlobalsAsDebuggees(JSContext*cx,unsignedargc,Value*vp);staticboolremoveDebuggee(JSContext*cx,unsignedargc,Value*vp);staticboolremoveAllDebuggees(JSContext*cx,unsignedargc,Value*vp);staticboolhasDebuggee(JSContext*cx,unsignedargc,Value*vp);staticboolgetDebuggees(JSContext*cx,unsignedargc,Value*vp);staticboolgetNewestFrame(JSContext*cx,unsignedargc,Value*vp);staticboolclearAllBreakpoints(JSContext*cx,unsignedargc,Value*vp);staticboolfindScripts(JSContext*cx,unsignedargc,Value*vp);staticboolfindObjects(JSContext*cx,unsignedargc,Value*vp);staticboolfindAllGlobals(JSContext*cx,unsignedargc,Value*vp);staticboolmakeGlobalObjectReference(JSContext*cx,unsignedargc,Value*vp);staticboolsetupTraceLoggerScriptCalls(JSContext*cx,unsignedargc,Value*vp);staticbooldrainTraceLoggerScriptCalls(JSContext*cx,unsignedargc,Value*vp);staticboolstartTraceLogger(JSContext*cx,unsignedargc,Value*vp);staticboolendTraceLogger(JSContext*cx,unsignedargc,Value*vp);staticboolisCompilableUnit(JSContext*cx,unsignedargc,Value*vp);#ifdef NIGHTLY_BUILDstaticboolsetupTraceLogger(JSContext*cx,unsignedargc,Value*vp);staticbooldrainTraceLogger(JSContext*cx,unsignedargc,Value*vp);#endifstaticbooladoptDebuggeeValue(JSContext*cx,unsignedargc,Value*vp);staticboolconstruct(JSContext*cx,unsignedargc,Value*vp);staticconstJSPropertySpecproperties[];staticconstJSFunctionSpecmethods[];staticconstJSFunctionSpecstatic_methods[];staticvoidremoveFromFrameMapsAndClearBreakpointsIn(JSContext*cx,AbstractFramePtrframe);staticboolupdateExecutionObservabilityOfFrames(JSContext*cx,constExecutionObservableSet&obs,IsObservingobserving);staticboolupdateExecutionObservabilityOfScripts(JSContext*cx,constExecutionObservableSet&obs,IsObservingobserving);staticboolupdateExecutionObservability(JSContext*cx,ExecutionObservableSet&obs,IsObservingobserving);template<typenameFrameFn/* void (NativeObject*) */>staticvoidforEachDebuggerFrame(AbstractFramePtrframe,FrameFnfn);/* * Return a vector containing all Debugger.Frame instances referring to * |frame|. |global| is |frame|'s global object; if nullptr or omitted, we * compute it ourselves from |frame|. */usingDebuggerFrameVector=GCVector<DebuggerFrame*>;staticMOZ_MUST_USEboolgetDebuggerFrames(AbstractFramePtrframe,MutableHandle<DebuggerFrameVector>frames);public:staticMOZ_MUST_USEboolensureExecutionObservabilityOfOsrFrame(JSContext*cx,InterpreterFrame*frame);// Public for DebuggerScript_setBreakpoint.staticMOZ_MUST_USEboolensureExecutionObservabilityOfScript(JSContext*cx,JSScript*script);// Whether the Debugger instance needs to observe all non-AOT JS// execution of its debugees.IsObservingobservesAllExecution()const;// Whether the Debugger instance needs to observe AOT-compiled asm.js// execution of its debuggees.IsObservingobservesAsmJS()const;// Whether the Debugger instance needs to observe coverage of any JavaScript// execution.IsObservingobservesCoverage()const;IsObservingobservesBinarySource()const;private:staticMOZ_MUST_USEboolensureExecutionObservabilityOfFrame(JSContext*cx,AbstractFramePtrframe);staticMOZ_MUST_USEboolensureExecutionObservabilityOfCompartment(JSContext*cx,JSCompartment*comp);staticboolhookObservesAllExecution(Hookwhich);MOZ_MUST_USEboolupdateObservesAllExecutionOnDebuggees(JSContext*cx,IsObservingobserving);MOZ_MUST_USEboolupdateObservesCoverageOnDebuggees(JSContext*cx,IsObservingobserving);voidupdateObservesAsmJSOnDebuggees(IsObservingobserving);voidupdateObservesBinarySourceDebuggees(IsObservingobserving);JSObject*getHook(Hookhook)const;boolhasAnyLiveHooks(JSRuntime*rt)const;staticMOZ_MUST_USEboolslowPathCheckNoExecute(JSContext*cx,HandleScriptscript);staticJSTrapStatusslowPathOnEnterFrame(JSContext*cx,AbstractFramePtrframe);staticMOZ_MUST_USEboolslowPathOnLeaveFrame(JSContext*cx,AbstractFramePtrframe,jsbytecode*pc,boolok);staticJSTrapStatusslowPathOnDebuggerStatement(JSContext*cx,AbstractFramePtrframe);staticJSTrapStatusslowPathOnExceptionUnwind(JSContext*cx,AbstractFramePtrframe);staticvoidslowPathOnNewScript(JSContext*cx,HandleScriptscript);staticvoidslowPathOnNewWasmInstance(JSContext*cx,Handle<WasmInstanceObject*>wasmInstance);staticvoidslowPathOnNewGlobalObject(JSContext*cx,Handle<GlobalObject*>global);staticMOZ_MUST_USEboolslowPathOnLogAllocationSite(JSContext*cx,HandleObjectobj,HandleSavedFrameframe,mozilla::TimeStampwhen,GlobalObject::DebuggerVector&dbgs);staticvoidslowPathPromiseHook(JSContext*cx,Hookhook,HandleObjectpromise);template<typenameHookIsEnabledFun/* bool (Debugger*) */,typenameFireHookFun/* JSTrapStatus (Debugger*) */>staticJSTrapStatusdispatchHook(JSContext*cx,HookIsEnabledFunhookIsEnabled,FireHookFunfireHook);JSTrapStatusfireDebuggerStatement(JSContext*cx,MutableHandleValuevp);JSTrapStatusfireExceptionUnwind(JSContext*cx,MutableHandleValuevp);JSTrapStatusfireEnterFrame(JSContext*cx,MutableHandleValuevp);JSTrapStatusfireNewGlobalObject(JSContext*cx,Handle<GlobalObject*>global,MutableHandleValuevp);JSTrapStatusfirePromiseHook(JSContext*cx,Hookhook,HandleObjectpromise,MutableHandleValuevp);NativeObject*newVariantWrapper(JSContext*cx,Handle<DebuggerScriptReferent>referent){returnnewDebuggerScript(cx,referent);}NativeObject*newVariantWrapper(JSContext*cx,Handle<DebuggerSourceReferent>referent){returnnewDebuggerSource(cx,referent);}/* * Helper function to help wrap Debugger objects whose referents may be * variants. Currently Debugger.Script and Debugger.Source referents may * be variants. * * Prefer using wrapScript, wrapWasmScript, wrapSource, and wrapWasmSource * whenever possible. */template<typenameReferentVariant,typenameReferent,typenameMap>JSObject*wrapVariantReferent(JSContext*cx,Map&map,Handle<CrossCompartmentKey>key,Handle<ReferentVariant>referent);JSObject*wrapVariantReferent(JSContext*cx,Handle<DebuggerScriptReferent>referent);JSObject*wrapVariantReferent(JSContext*cx,Handle<DebuggerSourceReferent>referent);/* * Allocate and initialize a Debugger.Script instance whose referent is * |referent|. */NativeObject*newDebuggerScript(JSContext*cx,Handle<DebuggerScriptReferent>referent);/* * Allocate and initialize a Debugger.Source instance whose referent is * |referent|. */NativeObject*newDebuggerSource(JSContext*cx,Handle<DebuggerSourceReferent>referent);/* * Receive a "new script" event from the engine. A new script was compiled * or deserialized. */voidfireNewScript(JSContext*cx,Handle<DebuggerScriptReferent>scriptReferent);/* * Receive a "garbage collection" event from the engine. A GC cycle with the * given data was recently completed. */voidfireOnGarbageCollectionHook(JSContext*cx,constJS::dbg::GarbageCollectionEvent::Ptr&gcData);/* * Gets a Debugger.Frame object. If maybeIter is non-null, we eagerly copy * its data if we need to make a new Debugger.Frame. */MOZ_MUST_USEboolgetScriptFrameWithIter(JSContext*cx,AbstractFramePtrframe,constFrameIter*maybeIter,MutableHandleValuevp);MOZ_MUST_USEboolgetScriptFrameWithIter(JSContext*cx,AbstractFramePtrframe,constFrameIter*maybeIter,MutableHandleDebuggerFrameresult);inlineBreakpoint*firstBreakpoint()const;staticMOZ_MUST_USEboolreplaceFrameGuts(JSContext*cx,AbstractFramePtrfrom,AbstractFramePtrto,ScriptFrameIter&iter);public:Debugger(JSContext*cx,NativeObject*dbg);~Debugger();MOZ_MUST_USEboolinit(JSContext*cx);inlineconstjs::GCPtrNativeObject&toJSObject()const;inlinejs::GCPtrNativeObject&toJSObjectRef();staticinlineDebugger*fromJSObject(constJSObject*obj);staticDebugger*fromChildJSObject(JSObject*obj);Zone*zone()const{returntoJSObject()->zone();}boolhasMemory()const;DebuggerMemory&memory()const;WeakGlobalObjectSet::RangeallDebuggees()const{returndebuggees.all();}/*********************************** Methods for interaction with the GC. *//* * A Debugger object is live if: * * the Debugger JSObject is live (Debugger::trace handles this case); OR * * it is in the middle of dispatching an event (the event dispatching * code roots it in this case); OR * * it is enabled, and it is debugging at least one live compartment, * and at least one of the following is true: * - it has a debugger hook installed * - it has a breakpoint set on a live script * - it has a watchpoint set on a live object. * * Debugger::markIteratively handles the last case. If it finds any Debugger * objects that are definitely live but not yet marked, it marks them and * returns true. If not, it returns false. */staticvoidtraceIncomingCrossCompartmentEdges(JSTracer*tracer);staticMOZ_MUST_USEboolmarkIteratively(GCMarker*marker);staticvoidtraceAllForMovingGC(JSTracer*trc);staticvoidsweepAll(FreeOp*fop);staticvoiddetachAllDebuggersFromGlobal(FreeOp*fop,GlobalObject*global);staticvoidfindZoneEdges(JS::Zone*v,gc::ZoneComponentFinder&finder);#ifdef DEBUGstaticboolisDebuggerCrossCompartmentEdge(JSObject*obj,constjs::gc::Cell*cell);#endif// Checks it the current compartment is allowed to execute code.staticinlineMOZ_MUST_USEboolcheckNoExecute(JSContext*cx,HandleScriptscript);/* * JSTrapStatus Overview * --------------------- * * The |onEnterFrame|, |onDebuggerStatement|, and |onExceptionUnwind| * methods below return a JSTrapStatus code that indicates how execution * should proceed: * * - JSTRAP_CONTINUE: Continue execution normally. * * - JSTRAP_THROW: Throw an exception. The method has set |cx|'s * pending exception to the value to be thrown. * * - JSTRAP_ERROR: Terminate execution (as is done when a script is terminated * for running too long). The method has cleared |cx|'s pending * exception. * * - JSTRAP_RETURN: Return from the new frame immediately. The method has * set the youngest JS frame's return value appropriately. *//* * Announce to the debugger that the context has entered a new JavaScript * frame, |frame|. Call whatever hooks have been registered to observe new * frames. */staticinlineJSTrapStatusonEnterFrame(JSContext*cx,AbstractFramePtrframe);/* * Announce to the debugger a |debugger;| statement on has been * encountered on the youngest JS frame on |cx|. Call whatever hooks have * been registered to observe this. * * Note that this method is called for all |debugger;| statements, * regardless of the frame's debuggee-ness. */staticinlineJSTrapStatusonDebuggerStatement(JSContext*cx,AbstractFramePtrframe);/* * Announce to the debugger that an exception has been thrown and propagated * to |frame|. Call whatever hooks have been registered to observe this. */staticinlineJSTrapStatusonExceptionUnwind(JSContext*cx,AbstractFramePtrframe);/* * Announce to the debugger that the thread has exited a JavaScript frame, |frame|. * If |ok| is true, the frame is returning normally; if |ok| is false, the frame * is throwing an exception or terminating. * * Change cx's current exception and |frame|'s return value to reflect the changes * in behavior the hooks request, if any. Return the new error/success value. * * This function may be called twice for the same outgoing frame; only the * first call has any effect. (Permitting double calls simplifies some * cases where an onPop handler's resumption value changes a return to a * throw, or vice versa: we can redirect to a complete copy of the * alternative path, containing its own call to onLeaveFrame.) */staticinlineMOZ_MUST_USEboolonLeaveFrame(JSContext*cx,AbstractFramePtrframe,jsbytecode*pc,boolok);staticinlinevoidonNewScript(JSContext*cx,HandleScriptscript);staticinlinevoidonNewWasmInstance(JSContext*cx,Handle<WasmInstanceObject*>wasmInstance);staticinlinevoidonNewGlobalObject(JSContext*cx,Handle<GlobalObject*>global);staticinlineMOZ_MUST_USEboolonLogAllocationSite(JSContext*cx,JSObject*obj,HandleSavedFrameframe,mozilla::TimeStampwhen);staticJSTrapStatusonTrap(JSContext*cx,MutableHandleValuevp);staticJSTrapStatusonSingleStep(JSContext*cx,MutableHandleValuevp);staticMOZ_MUST_USEboolhandleBaselineOsr(JSContext*cx,InterpreterFrame*from,jit::BaselineFrame*to);staticMOZ_MUST_USEboolhandleIonBailout(JSContext*cx,jit::RematerializedFrame*from,jit::BaselineFrame*to);staticvoidhandleUnrecoverableIonBailoutError(JSContext*cx,jit::RematerializedFrame*frame);staticvoidpropagateForcedReturn(JSContext*cx,AbstractFramePtrframe,HandleValuerval);staticboolhasLiveHook(GlobalObject*global,Hookwhich);staticboolinFrameMaps(AbstractFramePtrframe);/************************************* Functions for use by Debugger.cpp. */inlineboolobservesEnterFrame()const;inlineboolobservesNewScript()const;inlineboolobservesNewGlobalObject()const;inlineboolobservesGlobal(GlobalObject*global)const;boolobservesFrame(AbstractFramePtrframe)const;boolobservesFrame(constFrameIter&iter)const;boolobservesScript(JSScript*script)const;boolobservesWasm(wasm::Instance*instance)const;/* * If env is nullptr, call vp->setNull() and return true. Otherwise, find * or create a Debugger.Environment object for the given Env. On success, * store the Environment object in *vp and return true. */MOZ_MUST_USEboolwrapEnvironment(JSContext*cx,Handle<Env*>env,MutableHandleValuevp);MOZ_MUST_USEboolwrapEnvironment(JSContext*cx,Handle<Env*>env,MutableHandleDebuggerEnvironmentresult);/* * Like cx->compartment()->wrap(cx, vp), but for the debugger compartment. * * Preconditions: *vp is a value from a debuggee compartment; cx is in the * debugger's compartment. * * If *vp is an object, this produces a (new or existing) Debugger.Object * wrapper for it. Otherwise this is the same as JSCompartment::wrap. * * If *vp is a magic JS_OPTIMIZED_OUT value, this produces a plain object * of the form { optimizedOut: true }. * * If *vp is a magic JS_OPTIMIZED_ARGUMENTS value signifying missing * arguments, this produces a plain object of the form { missingArguments: * true }. * * If *vp is a magic JS_UNINITIALIZED_LEXICAL value signifying an * unaccessible uninitialized binding, this produces a plain object of the * form { uninitialized: true }. */MOZ_MUST_USEboolwrapDebuggeeValue(JSContext*cx,MutableHandleValuevp);MOZ_MUST_USEboolwrapDebuggeeObject(JSContext*cx,HandleObjectobj,MutableHandleDebuggerObjectresult);/* * Unwrap a Debug.Object, without rewrapping it for any particular debuggee * compartment. * * Preconditions: cx is in the debugger compartment. *vp is a value in that * compartment. (*vp should be a "debuggee value", meaning it is the * debugger's reflection of a value in the debuggee.) * * If *vp is a Debugger.Object, store the referent in *vp. Otherwise, if *vp * is an object, throw a TypeError, because it is not a debuggee * value. Otherwise *vp is a primitive, so leave it alone. * * When passing values from the debuggee to the debugger: * enter debugger compartment; * call wrapDebuggeeValue; // compartment- and debugger-wrapping * * When passing values from the debugger to the debuggee: * call unwrapDebuggeeValue; // debugger-unwrapping * enter debuggee compartment; * call cx->compartment()->wrap; // compartment-rewrapping * * (Extreme nerd sidebar: Unwrapping happens in two steps because there are * two different kinds of symmetry at work: regardless of which direction * we're going, we want any exceptions to be created and thrown in the * debugger compartment--mirror symmetry. But compartment wrapping always * happens in the target compartment--rotational symmetry.) */MOZ_MUST_USEboolunwrapDebuggeeValue(JSContext*cx,MutableHandleValuevp);MOZ_MUST_USEboolunwrapDebuggeeObject(JSContext*cx,MutableHandleObjectobj);MOZ_MUST_USEboolunwrapPropertyDescriptor(JSContext*cx,HandleObjectobj,MutableHandle<PropertyDescriptor>desc);/* * Store the Debugger.Frame object for frame in *vp. * * Use this if you have already access to a frame pointer without having * to incur the cost of walking the stack. */MOZ_MUST_USEboolgetScriptFrame(JSContext*cx,AbstractFramePtrframe,MutableHandleValuevp){returngetScriptFrameWithIter(cx,frame,nullptr,vp);}/* * Store the Debugger.Frame object for iter in *vp/result. Eagerly copies a * ScriptFrameIter::Data. * * Use this if you had to make a ScriptFrameIter to get the required * frame, in which case the cost of walking the stack has already been * paid. */MOZ_MUST_USEboolgetScriptFrame(JSContext*cx,constFrameIter&iter,MutableHandleValuevp){returngetScriptFrameWithIter(cx,iter.abstractFramePtr(),&iter,vp);}MOZ_MUST_USEboolgetScriptFrame(JSContext*cx,constFrameIter&iter,MutableHandleDebuggerFrameresult);/* * Set |*status| and |*value| to a (JSTrapStatus, Value) pair reflecting a * standard SpiderMonkey call state: a boolean success value |ok|, a return * value |rv|, and a context |cx| that may or may not have an exception set. * If an exception was pending on |cx|, it is cleared (and |ok| is asserted * to be false). */staticvoidresultToCompletion(JSContext*cx,boolok,constValue&rv,JSTrapStatus*status,MutableHandleValuevalue);/* * Set |*result| to a JavaScript completion value corresponding to |status| * and |value|. |value| should be the return value or exception value, not * wrapped as a debuggee value. |cx| must be in the debugger compartment. */MOZ_MUST_USEboolnewCompletionValue(JSContext*cx,JSTrapStatusstatus,constValue&value,MutableHandleValueresult);/* * Precondition: we are in the debuggee compartment (ac is entered) and ok * is true if the operation in the debuggee compartment succeeded, false on * error or exception. * * Postcondition: we are in the debugger compartment, having called * ac.leave() even if an error occurred. * * On success, a completion value is in vp and ac.context does not have a * pending exception. (This ordinarily returns true even if the ok argument * is false.) */MOZ_MUST_USEboolreceiveCompletionValue(mozilla::Maybe<AutoCompartment>&ac,boolok,HandleValueval,MutableHandleValuevp);/* * Return the Debugger.Script object for |script|, or create a new one if * needed. The context |cx| must be in the debugger compartment; |script| * must be a script in a debuggee compartment. */JSObject*wrapScript(JSContext*cx,HandleScriptscript);/* * Return the Debugger.Script object for |wasmInstance| (the toplevel * script), synthesizing a new one if needed. The context |cx| must be in * the debugger compartment; |wasmInstance| must be a WasmInstanceObject in * the debuggee compartment. */JSObject*wrapWasmScript(JSContext*cx,Handle<WasmInstanceObject*>wasmInstance);/* * Return the Debugger.Source object for |source|, or create a new one if * needed. The context |cx| must be in the debugger compartment; |source| * must be a script source object in a debuggee compartment. */JSObject*wrapSource(JSContext*cx,js::HandleScriptSourcesource);/* * Return the Debugger.Source object for |wasmInstance| (the entire module), * synthesizing a new one if needed. The context |cx| must be in the * debugger compartment; |wasmInstance| must be a WasmInstanceObject in the * debuggee compartment. */JSObject*wrapWasmSource(JSContext*cx,Handle<WasmInstanceObject*>wasmInstance);private:Debugger(constDebugger&)=delete;Debugger&operator=(constDebugger&)=delete;};enumclassDebuggerEnvironmentType{Declarative,With,Object};classDebuggerEnvironment:publicNativeObject{public:enum{OWNER_SLOT};staticconstunsignedRESERVED_SLOTS=1;staticconstClassclass_;staticNativeObject*initClass(JSContext*cx,HandleObjectdbgCtor,HandleObjectobjProto);staticDebuggerEnvironment*create(JSContext*cx,HandleObjectproto,HandleObjectreferent,HandleNativeObjectdebugger);DebuggerEnvironmentTypetype()const;MOZ_MUST_USEboolgetParent(JSContext*cx,MutableHandleDebuggerEnvironmentresult)const;MOZ_MUST_USEboolgetObject(JSContext*cx,MutableHandleDebuggerObjectresult)const;MOZ_MUST_USEboolgetCallee(JSContext*cx,MutableHandleDebuggerObjectresult)const;boolisDebuggee()const;boolisOptimized()const;staticMOZ_MUST_USEboolgetNames(JSContext*cx,HandleDebuggerEnvironmentenvironment,MutableHandle<IdVector>result);staticMOZ_MUST_USEboolfind(JSContext*cx,HandleDebuggerEnvironmentenvironment,HandleIdid,MutableHandleDebuggerEnvironmentresult);staticMOZ_MUST_USEboolgetVariable(JSContext*cx,HandleDebuggerEnvironmentenvironment,HandleIdid,MutableHandleValueresult);staticMOZ_MUST_USEboolsetVariable(JSContext*cx,HandleDebuggerEnvironmentenvironment,HandleIdid,HandleValuevalue);private:staticconstClassOpsclassOps_;staticconstJSPropertySpecproperties_[];staticconstJSFunctionSpecmethods_[];Env*referent()const{Env*env=static_cast<Env*>(getPrivate());MOZ_ASSERT(env);returnenv;}Debugger*owner()const;boolrequireDebuggee(JSContext*cx)const;staticMOZ_MUST_USEboolconstruct(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEbooltypeGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolparentGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolobjectGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolcalleeGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolinspectableGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEbooloptimizedOutGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolnamesMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolfindMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolgetVariableMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolsetVariableMethod(JSContext*cx,unsignedargc,Value*vp);};enumclassDebuggerFrameType{Eval,Global,Call,Module,WasmCall};enumclassDebuggerFrameImplementation{Interpreter,Baseline,Ion,Wasm};/* * A Handler represents a reference to a handler function. These handler * functions are called by the Debugger API to notify the user of certain * events. For each event type, we define a separate subclass of Handler. This * allows users to define a single reference to an object that implements * multiple handlers, by inheriting from the appropriate subclasses. * * A Handler can be stored on a reflection object, in which case the reflection * object becomes responsible for managing the lifetime of the Handler. To aid * with this, the Handler base class defines several methods, which are to be * called by the reflection object at the appropriate time (see below). */structHandler{virtual~Handler(){}/* * If the Handler is a reference to a callable JSObject, this method returns * the latter. This allows the Handler to be used from JS. Otherwise, this * method returns nullptr. */virtualJSObject*object()const=0;/* * Drops the reference to the handler. This method will be called by the * reflection object on which the reference is stored when the former is * finalized, or the latter replaced. */virtualvoiddrop()=0;/* * Traces the reference to the handler. This method will be called * by the reflection object on which the reference is stored whenever the * former is traced. */virtualvoidtrace(JSTracer*tracer)=0;};classDebuggerArguments:publicNativeObject{public:staticconstClassclass_;staticDebuggerArguments*create(JSContext*cx,HandleObjectproto,HandleDebuggerFrameframe);private:enum{FRAME_SLOT};staticconstunsignedRESERVED_SLOTS=1;};/* * An OnStepHandler represents a handler function that is called when a small * amount of progress is made in a frame. */structOnStepHandler:Handler{/* * If we have made a small amount of progress in a frame, this method is * called with the frame as argument. If succesful, this method should * return true, with `statusp` and `vp` set to a resumption value * specifiying how execution should continue. */virtualboolonStep(JSContext*cx,HandleDebuggerFrameframe,JSTrapStatus&statusp,MutableHandleValuevp)=0;};classScriptedOnStepHandlerfinal:publicOnStepHandler{public:explicitScriptedOnStepHandler(JSObject*object);virtualJSObject*object()constoverride;virtualvoiddrop()override;virtualvoidtrace(JSTracer*tracer)override;virtualboolonStep(JSContext*cx,HandleDebuggerFrameframe,JSTrapStatus&statusp,MutableHandleValuevp)override;private:HeapPtr<JSObject*>object_;};/* * An OnPopHandler represents a handler function that is called just before a * frame is popped. */structOnPopHandler:Handler{/* * If a frame is about the be popped, this method is called with the frame * as argument, and `statusp` and `vp` set to a completion value specifying * how this frame's execution completed. If successful, this method should * return true, with `statusp` and `vp` set to a resumption value specifying * how execution should continue. */virtualboolonPop(JSContext*cx,HandleDebuggerFrameframe,JSTrapStatus&statusp,MutableHandleValuevp)=0;};classScriptedOnPopHandlerfinal:publicOnPopHandler{public:explicitScriptedOnPopHandler(JSObject*object);virtualJSObject*object()constoverride;virtualvoiddrop()override;virtualvoidtrace(JSTracer*tracer)override;virtualboolonPop(JSContext*cx,HandleDebuggerFrameframe,JSTrapStatus&statusp,MutableHandleValuevp)override;private:HeapPtr<JSObject*>object_;};classDebuggerFrame:publicNativeObject{friendclassDebuggerArguments;friendclassScriptedOnStepHandler;friendclassScriptedOnPopHandler;public:enum{OWNER_SLOT};staticconstunsignedRESERVED_SLOTS=1;staticconstClassclass_;staticNativeObject*initClass(JSContext*cx,HandleObjectdbgCtor,HandleObjectobjProto);staticDebuggerFrame*create(JSContext*cx,HandleObjectproto,AbstractFramePtrreferent,constFrameIter*maybeIter,HandleNativeObjectdebugger);staticMOZ_MUST_USEboolgetArguments(JSContext*cx,HandleDebuggerFrameframe,MutableHandleDebuggerArgumentsresult);staticMOZ_MUST_USEboolgetCallee(JSContext*cx,HandleDebuggerFrameframe,MutableHandleDebuggerObjectresult);staticMOZ_MUST_USEboolgetIsConstructing(JSContext*cx,HandleDebuggerFrameframe,bool&result);staticMOZ_MUST_USEboolgetEnvironment(JSContext*cx,HandleDebuggerFrameframe,MutableHandleDebuggerEnvironmentresult);staticboolgetIsGenerator(HandleDebuggerFrameframe);staticMOZ_MUST_USEboolgetOffset(JSContext*cx,HandleDebuggerFrameframe,size_t&result);staticMOZ_MUST_USEboolgetOlder(JSContext*cx,HandleDebuggerFrameframe,MutableHandleDebuggerFrameresult);staticMOZ_MUST_USEboolgetThis(JSContext*cx,HandleDebuggerFrameframe,MutableHandleValueresult);staticDebuggerFrameTypegetType(HandleDebuggerFrameframe);staticDebuggerFrameImplementationgetImplementation(HandleDebuggerFrameframe);staticMOZ_MUST_USEboolsetOnStepHandler(JSContext*cx,HandleDebuggerFrameframe,OnStepHandler*handler);staticMOZ_MUST_USEbooleval(JSContext*cx,HandleDebuggerFrameframe,mozilla::Range<constchar16_t>chars,HandleObjectbindings,constEvalOptions&options,JSTrapStatus&status,MutableHandleValuevalue);boolisLive()const;OnStepHandler*onStepHandler()const;OnPopHandler*onPopHandler()const;voidsetOnPopHandler(OnPopHandler*handler);private:staticconstClassOpsclassOps_;staticconstJSPropertySpecproperties_[];staticconstJSFunctionSpecmethods_[];staticAbstractFramePtrgetReferent(HandleDebuggerFrameframe);staticMOZ_MUST_USEboolgetFrameIter(JSContext*cx,HandleDebuggerFrameframe,mozilla::Maybe<FrameIter>&result);staticMOZ_MUST_USEboolrequireScriptReferent(JSContext*cx,HandleDebuggerFrameframe);staticMOZ_MUST_USEboolconstruct(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolargumentsGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolcalleeGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolconstructingGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolenvironmentGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolgeneratorGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolliveGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEbooloffsetGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboololderGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolthisGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEbooltypeGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolimplementationGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolonStepGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolonStepSetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolonPopGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolonPopSetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolevalMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolevalWithBindingsMethod(JSContext*cx,unsignedargc,Value*vp);Debugger*owner()const;};classDebuggerObject:publicNativeObject{public:staticconstClassclass_;staticNativeObject*initClass(JSContext*cx,HandleObjectobj,HandleObjectdebugCtor);staticDebuggerObject*create(JSContext*cx,HandleObjectproto,HandleObjectobj,HandleNativeObjectdebugger);// PropertiesstaticMOZ_MUST_USEboolgetClassName(JSContext*cx,HandleDebuggerObjectobject,MutableHandleStringresult);staticMOZ_MUST_USEboolgetGlobal(JSContext*cx,HandleDebuggerObjectobject,MutableHandleDebuggerObjectresult);staticMOZ_MUST_USEboolgetParameterNames(JSContext*cx,HandleDebuggerObjectobject,MutableHandle<StringVector>result);staticMOZ_MUST_USEboolgetBoundTargetFunction(JSContext*cx,HandleDebuggerObjectobject,MutableHandleDebuggerObjectresult);staticMOZ_MUST_USEboolgetBoundThis(JSContext*cx,HandleDebuggerObjectobject,MutableHandleValueresult);staticMOZ_MUST_USEboolgetBoundArguments(JSContext*cx,HandleDebuggerObjectobject,MutableHandle<ValueVector>result);staticMOZ_MUST_USEboolgetAllocationSite(JSContext*cx,HandleDebuggerObjectobject,MutableHandleObjectresult);staticMOZ_MUST_USEboolgetErrorMessageName(JSContext*cx,HandleDebuggerObjectobject,MutableHandleStringresult);staticMOZ_MUST_USEboolgetErrorNotes(JSContext*cx,HandleDebuggerObjectobject,MutableHandleValueresult);staticMOZ_MUST_USEboolgetErrorLineNumber(JSContext*cx,HandleDebuggerObjectobject,MutableHandleValueresult);staticMOZ_MUST_USEboolgetErrorColumnNumber(JSContext*cx,HandleDebuggerObjectobject,MutableHandleValueresult);staticMOZ_MUST_USEboolgetScriptedProxyTarget(JSContext*cx,HandleDebuggerObjectobject,MutableHandleDebuggerObjectresult);staticMOZ_MUST_USEboolgetScriptedProxyHandler(JSContext*cx,HandleDebuggerObjectobject,MutableHandleDebuggerObjectresult);staticMOZ_MUST_USEboolgetPromiseValue(JSContext*cx,HandleDebuggerObjectobject,MutableHandleValueresult);staticMOZ_MUST_USEboolgetPromiseReason(JSContext*cx,HandleDebuggerObjectobject,MutableHandleValueresult);// MethodsstaticMOZ_MUST_USEboolisExtensible(JSContext*cx,HandleDebuggerObjectobject,bool&result);staticMOZ_MUST_USEboolisSealed(JSContext*cx,HandleDebuggerObjectobject,bool&result);staticMOZ_MUST_USEboolisFrozen(JSContext*cx,HandleDebuggerObjectobject,bool&result);staticMOZ_MUST_USEboolgetPrototypeOf(JSContext*cx,HandleDebuggerObjectobject,MutableHandleDebuggerObjectresult);staticMOZ_MUST_USEboolgetOwnPropertyNames(JSContext*cx,HandleDebuggerObjectobject,MutableHandle<IdVector>result);staticMOZ_MUST_USEboolgetOwnPropertySymbols(JSContext*cx,HandleDebuggerObjectobject,MutableHandle<IdVector>result);staticMOZ_MUST_USEboolgetOwnPropertyDescriptor(JSContext*cx,HandleDebuggerObjectobject,HandleIdid,MutableHandle<PropertyDescriptor>desc);staticMOZ_MUST_USEboolpreventExtensions(JSContext*cx,HandleDebuggerObjectobject);staticMOZ_MUST_USEboolseal(JSContext*cx,HandleDebuggerObjectobject);staticMOZ_MUST_USEboolfreeze(JSContext*cx,HandleDebuggerObjectobject);staticMOZ_MUST_USEbooldefineProperty(JSContext*cx,HandleDebuggerObjectobject,HandleIdid,Handle<PropertyDescriptor>desc);staticMOZ_MUST_USEbooldefineProperties(JSContext*cx,HandleDebuggerObjectobject,Handle<IdVector>ids,Handle<PropertyDescriptorVector>descs);staticMOZ_MUST_USEbooldeleteProperty(JSContext*cx,HandleDebuggerObjectobject,HandleIdid,ObjectOpResult&result);staticMOZ_MUST_USEboolcall(JSContext*cx,HandleDebuggerObjectobject,HandleValuethisv,Handle<ValueVector>args,MutableHandleValueresult);staticMOZ_MUST_USEboolforceLexicalInitializationByName(JSContext*cx,HandleDebuggerObjectobject,HandleIdid,bool&result);staticMOZ_MUST_USEboolexecuteInGlobal(JSContext*cx,HandleDebuggerObjectobject,mozilla::Range<constchar16_t>chars,HandleObjectbindings,constEvalOptions&options,JSTrapStatus&status,MutableHandleValuevalue);staticMOZ_MUST_USEboolmakeDebuggeeValue(JSContext*cx,HandleDebuggerObjectobject,HandleValuevalue,MutableHandleValueresult);staticMOZ_MUST_USEboolunsafeDereference(JSContext*cx,HandleDebuggerObjectobject,MutableHandleObjectresult);staticMOZ_MUST_USEboolunwrap(JSContext*cx,HandleDebuggerObjectobject,MutableHandleDebuggerObjectresult);// Infallible propertiesboolisCallable()const;boolisFunction()const;boolisDebuggeeFunction()const;boolisBoundFunction()const;boolisArrowFunction()const;boolisGlobal()const;boolisScriptedProxy()const;boolisPromise()const;JSAtom*name(JSContext*cx)const;JSAtom*displayName(JSContext*cx)const;JS::PromiseStatepromiseState()const;doublepromiseLifetime()const;doublepromiseTimeToResolution()const;private:enum{OWNER_SLOT};staticconstunsignedRESERVED_SLOTS=1;staticconstClassOpsclassOps_;staticconstJSPropertySpecproperties_[];staticconstJSPropertySpecpromiseProperties_[];staticconstJSFunctionSpecmethods_[];JSObject*referent()const{JSObject*obj=(JSObject*)getPrivate();MOZ_ASSERT(obj);returnobj;}Debugger*owner()const;PromiseObject*promise()const;staticMOZ_MUST_USEboolrequireGlobal(JSContext*cx,HandleDebuggerObjectobject);staticMOZ_MUST_USEboolrequirePromise(JSContext*cx,HandleDebuggerObjectobject);staticMOZ_MUST_USEboolconstruct(JSContext*cx,unsignedargc,Value*vp);// JSNative propertiesstaticMOZ_MUST_USEboolcallableGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolisBoundFunctionGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolisArrowFunctionGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolprotoGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolclassGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolnameGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEbooldisplayNameGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolparameterNamesGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolscriptGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolenvironmentGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolboundTargetFunctionGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolboundThisGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolboundArgumentsGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolglobalGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolallocationSiteGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolerrorMessageNameGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolerrorNotesGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolerrorLineNumberGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolerrorColumnNumberGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolisProxyGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolproxyTargetGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolproxyHandlerGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolisPromiseGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseStateGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseValueGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseReasonGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseLifetimeGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseTimeToResolutionGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseAllocationSiteGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseResolutionSiteGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseIDGetter(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpromiseDependentPromisesGetter(JSContext*cx,unsignedargc,Value*vp);// JSNative methodsstaticMOZ_MUST_USEboolisExtensibleMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolisSealedMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolisFrozenMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolgetOwnPropertyNamesMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolgetOwnPropertySymbolsMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolgetOwnPropertyDescriptorMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolpreventExtensionsMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolsealMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolfreezeMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEbooldefinePropertyMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEbooldefinePropertiesMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEbooldeletePropertyMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolcallMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolapplyMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolasEnvironmentMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolforceLexicalInitializationByNameMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolexecuteInGlobalMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolexecuteInGlobalWithBindingsMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolmakeDebuggeeValueMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolunsafeDereferenceMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolunwrapMethod(JSContext*cx,unsignedargc,Value*vp);staticMOZ_MUST_USEboolgetErrorReport(JSContext*cx,HandleObjectmaybeError,JSErrorReport*&report);};classJSBreakpointSite;classWasmBreakpoint;classWasmBreakpointSite;classBreakpointSite{friendclassBreakpoint;friendstruct::JSCompartment;friendclass::JSScript;friendclassDebugger;public:enumclassType{JS,Wasm};private:Typetype_;template<typenameT>structSiteSiblingAccess{staticT*GetNext(T*elm){returnelm->siteLink.mNext;}staticvoidSetNext(T*elm,T*next){elm->siteLink.mNext=next;}staticT*GetPrev(T*elm){returnelm->siteLink.mPrev;}staticvoidSetPrev(T*elm,T*prev){elm->siteLink.mPrev=prev;}};// List of all js::Breakpoints at this instruction.usingBreakpointList=mozilla::DoublyLinkedList<js::Breakpoint,SiteSiblingAccess<js::Breakpoint>>;BreakpointListbreakpoints;size_tenabledCount;/* number of breakpoints in the list that are enabled */protected:virtualvoidrecompile(FreeOp*fop)=0;boolisEmpty()const;inlineboolisEnabled()const{returnenabledCount>0;}public:BreakpointSite(Typetype);Breakpoint*firstBreakpoint()const;virtual~BreakpointSite(){}boolhasBreakpoint(Breakpoint*bp);inlineTypetype()const{returntype_;}voidinc(FreeOp*fop);voiddec(FreeOp*fop);virtualvoiddestroyIfEmpty(FreeOp*fop)=0;inlineJSBreakpointSite*asJS();inlineWasmBreakpointSite*asWasm();};/* * Each Breakpoint is a member of two linked lists: its debugger's list and its * site's list. * * GC rules: * - script is live, breakpoint exists, and debugger is enabled * ==> debugger is live * - script is live, breakpoint exists, and debugger is live * ==> retain the breakpoint and the handler object is live * * Debugger::markIteratively implements these two rules. It uses * Debugger::hasAnyLiveHooks to check for rule 1. * * Nothing else causes a breakpoint to be retained, so if its script or * debugger is collected, the breakpoint is destroyed during GC sweep phase, * even if the debugger compartment isn't being GC'd. This is implemented in * Zone::sweepBreakpoints. */classBreakpoint{friendstruct::JSCompartment;friendclassDebugger;friendclassBreakpointSite;public:Debugger*constdebugger;BreakpointSite*constsite;private:/* |handler| is marked unconditionally during minor GC. */js::PreBarrieredObjecthandler;/** * Link elements for each list this breakpoint can be in. */mozilla::DoublyLinkedListElement<Breakpoint>debuggerLink;mozilla::DoublyLinkedListElement<Breakpoint>siteLink;public:Breakpoint(Debugger*debugger,BreakpointSite*site,JSObject*handler);voiddestroy(FreeOp*fop);Breakpoint*nextInDebugger();Breakpoint*nextInSite();constPreBarrieredObject&getHandler()const{returnhandler;}PreBarrieredObject&getHandlerRef(){returnhandler;}inlineWasmBreakpoint*asWasm();};classJSBreakpointSite:publicBreakpointSite{public:JSScript*script;jsbytecode*constpc;protected:voidrecompile(FreeOp*fop)override;public:JSBreakpointSite(JSScript*script,jsbytecode*pc);voiddestroyIfEmpty(FreeOp*fop)override;};inlineJSBreakpointSite*BreakpointSite::asJS(){MOZ_ASSERT(type()==Type::JS);returnstatic_cast<JSBreakpointSite*>(this);}classWasmBreakpointSite:publicBreakpointSite{public:wasm::DebugState*debug;uint32_toffset;protected:voidrecompile(FreeOp*fop)override;public:WasmBreakpointSite(wasm::DebugState*debug,uint32_toffset);voiddestroyIfEmpty(FreeOp*fop)override;};inlineWasmBreakpointSite*BreakpointSite::asWasm(){MOZ_ASSERT(type()==Type::Wasm);returnstatic_cast<WasmBreakpointSite*>(this);}classWasmBreakpoint:publicBreakpoint{public:WasmInstanceObject*wasmInstance;WasmBreakpoint(Debugger*debugger,WasmBreakpointSite*site,JSObject*handler,WasmInstanceObject*wasmInstance_):Breakpoint(debugger,site,handler),wasmInstance(wasmInstance_){}};inlineWasmBreakpoint*Breakpoint::asWasm(){MOZ_ASSERT(site&&site->type()==BreakpointSite::Type::Wasm);returnstatic_cast<WasmBreakpoint*>(this);}Breakpoint*Debugger::firstBreakpoint()const{if(breakpoints.isEmpty())returnnullptr;return&(*breakpoints.begin());}constjs::GCPtrNativeObject&Debugger::toJSObject()const{MOZ_ASSERT(object);returnobject;}js::GCPtrNativeObject&Debugger::toJSObjectRef(){MOZ_ASSERT(object);returnobject;}boolDebugger::observesEnterFrame()const{returnenabled&&getHook(OnEnterFrame);}boolDebugger::observesNewScript()const{returnenabled&&getHook(OnNewScript);}boolDebugger::observesNewGlobalObject()const{returnenabled&&getHook(OnNewGlobalObject);}boolDebugger::observesGlobal(GlobalObject*global)const{ReadBarriered<GlobalObject*>debuggee(global);returndebuggees.has(debuggee);}/* static */voidDebugger::onNewScript(JSContext*cx,HandleScriptscript){// We early return in slowPathOnNewScript for self-hosted scripts, so we can// ignore those in our assertion here.MOZ_ASSERT_IF(!script->compartment()->creationOptions().invisibleToDebugger()&&!script->selfHosted(),script->compartment()->firedOnNewGlobalObject);if(script->compartment()->isDebuggee())slowPathOnNewScript(cx,script);}/* static */voidDebugger::onNewGlobalObject(JSContext*cx,Handle<GlobalObject*>global){MOZ_ASSERT(!global->compartment()->firedOnNewGlobalObject);#ifdef DEBUGglobal->compartment()->firedOnNewGlobalObject=true;#endifif(!cx->runtime()->onNewGlobalObjectWatchers().isEmpty())Debugger::slowPathOnNewGlobalObject(cx,global);}/* static */boolDebugger::onLogAllocationSite(JSContext*cx,JSObject*obj,HandleSavedFrameframe,mozilla::TimeStampwhen){GlobalObject::DebuggerVector*dbgs=cx->global()->getDebuggers();if(!dbgs||dbgs->empty())returntrue;RootedObjecthobj(cx,obj);returnDebugger::slowPathOnLogAllocationSite(cx,hobj,frame,when,*dbgs);}MOZ_MUST_USEboolReportObjectRequired(JSContext*cx);}/* namespace js */namespaceJS{template<>structDeletePolicy<js::Debugger>:publicjs::GCManagedDeletePolicy<js::Debugger>{};}/* namespace JS */#endif /* vm_Debugger_h */